/*
 * Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include <unistd.h>
#include "sle_advanced_setting_manager.h"
#include "sle_connect_manager.h"
#include "sle_hilog.h"

namespace OHOS {
namespace NearLink {
namespace SleStandard {
namespace {
constexpr uint32_t NOT_EXCHANGE_MTU_SIZE = 0;
constexpr uint32_t COVER_MTU_SIZE_1500 = 1460;
constexpr uint32_t COVER_MTU_SIZE_512 = 460;
constexpr double COVER_MTU_FACTOR= 0.9;
constexpr const char *SLE_ADVANCED_RUNNER_WORK_THREAD = "SLE_ADVANCED_RUNNER_WORK_THREAD";
}

AdvancedSettingManager::AdvancedSettingManager()
{

}

AdvancedSettingManager::~AdvancedSettingManager()
{

}

AdvancedSettingManager *AdvancedSettingManager::GetInstance()
{
    static AdvancedSettingManager instance;
    return &instance;
}

void AdvancedSettingManager::InitAdvancedSettingManager()
{
    advancedEventRunner_ = AppExecFwk::EventRunner::Create(SLE_ADVANCED_RUNNER_WORK_THREAD);
    SLE_ASSERT_AND_RETURN_LOG(advancedEventRunner_ != nullptr, "create advancedEventRunner_ fail");
    advancedEventHandler_ = std::make_shared<SleEventHandler>(advancedEventRunner_);
    SLE_ASSERT_AND_RETURN_LOG(advancedEventHandler_ != nullptr, "create advancedEventHandler_ fail");
    SLE_LOGI("AdvancedSettingManager InitAdvancedSettingManager ok");

    connCfgMgr_ = std::make_unique<SleConnectConfigManager>();
    SLE_ASSERT_AND_RETURN_LOG(connCfgMgr_ != nullptr, "create connCfgMgr_ fail");
    announceCfgMgr_ = std::make_unique<SleAnnounceConfigManager>();
    SLE_ASSERT_AND_RETURN_LOG(announceCfgMgr_ != nullptr, "create announceCfgMgr_ fail");
    seekCfgMgr_ = std::make_unique<SleSeekConfigManager>();
    SLE_ASSERT_AND_RETURN_LOG(seekCfgMgr_ != nullptr, "create seekCfgMgr_ fail");

    SleErrorCode result = connCfgMgr_->GetConnectLocalModeConfig(connectModeConfig_);
    SLE_ASSERT_AND_RETURN_LOG(result == SLE_NO_ERROR, "get connectModeConfig_ failed!");
    result = connCfgMgr_->GetConnectConfig(connectConfig_);
    SLE_ASSERT_AND_RETURN_LOG(result == SLE_NO_ERROR, "get connectConfig_ failed!");
    result = connCfgMgr_->GetConnectDefaultConfig(defaultConfig_);
    SLE_ASSERT_AND_RETURN_LOG(result == SLE_NO_ERROR, "get defaultConfig_ failed!");
    result = announceCfgMgr_->GetAnnounceConfig(announceConfig_);
    SLE_ASSERT_AND_RETURN_LOG(result == SLE_NO_ERROR, "get announceConfig_ failed!");
    result = seekCfgMgr_->GetSeekConfig(seekConfig_);
    SLE_ASSERT_AND_RETURN_LOG(result == SLE_NO_ERROR, "get seekConfig_ failed!");
}

SleErrorCode AdvancedSettingManager::ASProcessSleStateChange(SleDeviceState state)
{
    SLE_LOGI("ASProcessSleStateChange, state = %{public}d", state);
    return SLE_NO_ERROR;
}

SleErrorCode AdvancedSettingManager::ASProcessConnectStateChange(uint16_t connectId, const SleAddress &address,
        SleConnectState state, SlePairState pairState, SleDisConnectReason reason)
{
    SleDeviceAddress addrDev = address.ConvertToSleDeviceAddress();
    SLE_LOGI("ASProcessConnectStateChange connectId = %{public}d, addr = " MACSTR", connState = %{public}s(%{public}d), "
        "pairState = %{public}s(%{public}d), discReason = %{public}s(%{public}hhu)", connectId, MAC2STR(addrDev.addr),
        SleConnectStateStr(state), state, SlePairStateStr(pairState), pairState, SleDisConnectReasonStr(reason), reason);
    //设置默认参数
    // SetDefaultConnParam();
    if (state == SLE_CONNECT_DISCONNECTED_STATE) {
        RemoveRecomSendDataToMap(connectId);//clear connectId -- sendDataSize
    }
    return SLE_NO_ERROR;
}

SleErrorCode AdvancedSettingManager::ASProcessConnParamUpdateComplete
        (uint16_t connectId, const SleConnectionParamUpdateEvt &param, SleErrorCode errCode)
{
    SLE_LOGI("ASProcessConnParamUpdateComplete connectId = %{public}d, errCode = %{public}hhu, connInterval = %{public}d,"
             " connLatency = %{public}d, connTimeout = %{public}d", connectId, errCode, param.interval, param.latency,
             param.supervisionTimeout);
    return SLE_NO_ERROR;
}

SleErrorCode AdvancedSettingManager::ASProcessSsapcExchangeInfo
        (uint8_t clientId, uint16_t connectId, const SsapMtuInfo &info, SleErrorCode errCode)
{
    SLE_LOGI("ASProcessSsapcExchangeInfo, clientId = %{public}d, connectId = %{public}d, mtuSize = %{public}d, "
             "errCode = %{public}d", clientId, connectId, info.mtuSize, errCode);
    if (errCode == SLE_NO_ERROR) {
        SetSendDataSize(connectId, info.mtuSize);
    }
    return SLE_NO_ERROR;
}

SleErrorCode AdvancedSettingManager::ASProcessSsapsMtuInfoChanged
        (uint8_t serverId, uint16_t connectId, const SsapMtuInfo &info, SleErrorCode errCode)
{
    SLE_LOGI("ASProcessSsapsMtuInfoChanged, serverId = %{public}d, connectId = %{public}d, mtuSize = %{public}d, "
             "errCode = %{public}d", serverId, connectId, info.mtuSize, errCode);
    if (errCode == SLE_NO_ERROR) {
        SetSendDataSize(connectId, info.mtuSize);
    }
    return SLE_NO_ERROR;
}

SleErrorCode AdvancedSettingManager::UpdateAllConnectParam(std::vector<SleConnectDevice> &successUpdateDev)
{
    SleConnectParam updateParam;
    SleErrorCode ret = CalculateConnParam(updateParam);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, SLE_ERR_FAILED, "CalculateConnParam failed!");
    SleConnectionParam params(updateParam);

    std::vector<SleConnectDevice> connectedDevList;
    uint16_t connectedNum = 0;
    ret = GetConnectedDeviceList(connectedDevList, connectedNum);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, SLE_ERR_FAILED, "GetConnectedDeviceList failed!");
    SLE_LOGD("UpdateAllConnectParam In, the update device num = %{public}d", connectedNum);
    for (auto & dev : connectedDevList) {
        if (advancedEventHandler_) {
            advancedEventHandler_->PostSyncTask(
                [dev, params, &ret]() {
                    ret = SleConnectManager::GetInstance()->UpdateConnectParam(dev.connectId_, params);
                });
        }
        if (ret != SLE_NO_ERROR) {
            SLE_LOGE("update param connId[%{public}d] failed!", dev.connectId_);
            continue;
        }
        successUpdateDev.emplace_back(dev);
    }
    SLE_LOGD("UpdateAllConnectParam out");
    return SLE_NO_ERROR;
}

SleErrorCode AdvancedSettingManager::GetRecomSendDataSize(uint16_t connectId, uint32_t &recomSendDataSize)
{
    std::lock_guard<std::mutex> lock(sizeLock_);
    auto it = packageLenMap_.find(connectId);
    if (it != packageLenMap_.end()) {
        recomSendDataSize = it->second;
    } else {
        recomSendDataSize = NOT_EXCHANGE_MTU_SIZE;
    }
    return SLE_NO_ERROR;
}

SleErrorCode AdvancedSettingManager::GetHostDefaultConnectConfig(SleConnectConfig &connParamConfig)
{
    SLE_ASSERT_AND_RETURN_RET_LOG(connCfgMgr_ != nullptr, SLE_ERR_INVALID_PARAM, "connCfgMgr_ nullptr error!");
    return connCfgMgr_->GetConnectConfig(connParamConfig);
}

SleErrorCode AdvancedSettingManager::GetDefaultSeekParamConfig(SleSeekParam &seekParam)
{
    SLE_ASSERT_AND_RETURN_RET_LOG(seekCfgMgr_ != nullptr, SLE_ERR_INVALID_PARAM, "seekCfgMgr_ nullptr error!");
    return seekCfgMgr_->GetSeekConfig(seekParam);
}

SleErrorCode AdvancedSettingManager::GetDefaultAnnounceParamConfig(SleAnnounceParam &announceConfig)
{
    SLE_ASSERT_AND_RETURN_RET_LOG(announceCfgMgr_ != nullptr, SLE_ERR_INVALID_PARAM, "announceCfgMgr_ nullptr error!");
    return announceCfgMgr_->GetAnnounceConfig(announceConfig);
}

void AdvancedSettingManager::RemoveRecomSendDataToMap(uint16_t connectId)
{
    std::lock_guard<std::mutex> lock(sizeLock_);
    auto it = packageLenMap_.find(connectId);
    if (it != packageLenMap_.end()) {
        packageLenMap_.erase(connectId);
    }
}

SleErrorCode AdvancedSettingManager::SetSendDataSize(uint16_t connectId, uint32_t mtu)
{
    std::lock_guard<std::mutex> lock(sizeLock_);
    uint32_t dataSize = ConvertMtuToDataSize(mtu);
    auto it = packageLenMap_.find(connectId);
    if (it != packageLenMap_.end()) {
        it->second = mtu;
    } else {
        packageLenMap_.insert(std::make_pair(connectId, dataSize));
    }
    return SLE_NO_ERROR;
}

uint32_t AdvancedSettingManager::ConvertMtuToDataSize(uint32_t mtuSize)
{
    uint32_t dataSize = 0;
    switch (mtuSize) {
        case 1500:
            dataSize = COVER_MTU_SIZE_1500;
            break;
        case 512:
            dataSize = COVER_MTU_SIZE_512;
            break;
        default:
            dataSize = static_cast<uint32_t>(mtuSize * COVER_MTU_FACTOR);
            break;
    }
    return dataSize;
}

uint16_t AdvancedSettingManager::CalculateConnInterval(uint16_t stepCount, uint16_t stepPeriod, uint16_t devNum)
{
    uint16_t res = 0;
    res = static_cast<uint32_t>(stepPeriod * pow(2, static_cast<double>(devNum) / stepCount)) +
          static_cast<uint32_t>(stepPeriod / 2) * (devNum % stepCount) * (devNum - 1) - (devNum * devNum);
    return res;
}

SleErrorCode AdvancedSettingManager::CalculateConnParam(SleConnectParam &param)
{
    std::vector<SleConnectDevice> connectedDevList;
    uint16_t connectedNum = 0;
    SleErrorCode ret = GetConnectedDeviceList(connectedDevList, connectedNum);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, SLE_ERR_FAILED, "GetConnectedDeviceList failed!");
    SLE_ASSERT_AND_RETURN_RET_LOG(connectedNum != 0, SLE_ERR_FAILED, "the connectedNum is 0, no need UpdateAllConnectParam!");

    param.intervalMin = CalculateConnInterval(connectModeConfig_.stepCount, connectModeConfig_.stepPeriod, connectedNum);
    param.intervalMax = param.intervalMin;
    param.latency = 0;
    param.supervisionTimeout = 500;
    SLE_LOGI("the CalculateConnParam is %{public}d", param.intervalMin);
    return SLE_NO_ERROR;
}

SleErrorCode AdvancedSettingManager::GetConnectedDeviceList(std::vector<SleConnectDevice> &devices, uint16_t &number)
{
    std::vector<SleConnectDevice> connectDevList;
    uint16_t connectNum = SLE_MAX_CONNECT_ID_NUM;
    SleErrorCode ret = SleConnectManager::GetInstance()->GetConnectDeviceList(connectDevList, connectNum);
    if(ret != SLE_NO_ERROR) {
        SLE_LOGE("GetConnectDevList failed, ret:%{public}hhu", ret);
        return ret;
    }
    for (auto & dev : connectDevList) {
        if (dev.connectId_ == 0xFFFF) {
            continue;
        }
        devices.emplace_back(dev);
    }
    number = devices.size();
    return SLE_NO_ERROR;
}

SleErrorCode AdvancedSettingManager::GetDefaultConnParam(SleDefaultConnectionParam &defaultConnParam)
{
    SleConnectParam updateParam;
    SleErrorCode ret = CalculateConnParam(updateParam);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, SLE_ERR_FAILED, "CalculateConnParam failed!");
    defaultConnParam.min_interval = updateParam.intervalMin;
    defaultConnParam.max_interval = updateParam.intervalMax;
    defaultConnParam.enable_filter_policy = defaultConfig_.enable_filter_policy;
    defaultConnParam.initiate_phys = defaultConfig_.initiate_phys;
    defaultConnParam.gt_negotiate = defaultConfig_.gt_negotiate;
    defaultConnParam.scan_interval = defaultConfig_.scan_interval;
    defaultConnParam.scan_window = defaultConfig_.scan_window;
    defaultConnParam.timeout = defaultConfig_.timeout;
    return SLE_NO_ERROR;
}

SleErrorCode AdvancedSettingManager::SetDefaultConnParam()
{
    SLE_LOGD("SetDefaultConnParam in");
    SleDefaultConnectionParam defaultConnParam = {0};
    SleErrorCode ret = GetDefaultConnParam(defaultConnParam);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, SLE_ERR_FAILED, "GetDefaultConnParam failed, return!");
    ret = SleConnectService::GetInstance()->SetDefaultConnParam(defaultConnParam);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "SetDefaultConnParam failed(%{public}d)!", ret);
    return ret;
}

}
}
}